# code=utf-8

from python_gossip.gossip_node import GossipNode


class GossipNetwork:
    """Gossip 网络管理器"""

    def __init__(self):
        self.nodes: Dict[str, GossipNode] = {}

    def create_node(self, node_id: str, host: str = 'localhost', port: int = None):
        """创建新节点"""
        if port is None:
            # 自动选择端口
            port = 8000 + len(self.nodes)

        # 检查端口是否被占用
        while self._is_port_used(host, port):
            port += 1

        node = GossipNode(node_id, host, port)
        self.nodes[node_id] = node
        return node

    def _is_port_used(self, host: str, port: int) -> bool:
        """检查端口是否被使用"""
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
                s.bind((host, port))
            return False
        except socket.error:
            return True

    def connect_nodes(self, node1_id: str, node2_id: str):
        """连接两个节点"""
        if node1_id in self.nodes and node2_id in self.nodes:
            node1 = self.nodes[node1_id]
            node2 = self.nodes[node2_id]

            node1.add_peer(node2.address)
            node2.add_peer(node1.address)

            logger.info(f"Connected {node1_id} and {node2_id}")

    def start_network(self):
        """启动所有节点"""
        for node_id, node in self.nodes.items():
            try:
                node.start()
                time.sleep(0.1)  # 短暂延迟避免端口冲突
            except Exception as e:
                logger.error(f"Failed to start node {node_id}: {e}")

    def stop_network(self):
        """停止所有节点"""
        for node in self.nodes.values():
            node.stop()

    def get_network_status(self):
        """获取网络状态"""
        status = {}
        for node_id, node in self.nodes.items():
            status[node_id] = node.get_status()
        return status


def demo_gossip_network():
    """演示 Gossip 网络"""
    print("=== Gossip 网络演示 ===")

    network = GossipNetwork()

    # 创建4个节点
    nodes = []
    for i in range(4):
        node_id = f"node_{i}"
        node = network.create_node(node_id, 'localhost', 8000 + i)
        nodes.append(node)

    # 建立连接（形成环状网络）
    for i in range(4):
        network.connect_nodes(f"node_{i}", f"node_{(i + 1) % 4}")

    # 启动网络
    network.start_network()

    # 等待节点启动
    time.sleep(2)

    # 在不同节点上存储数据
    print("\n--- 存储初始数据 ---")
    network.nodes['node_0'].put_data('config_db_host', 'db1.example.com')
    network.nodes['node_1'].put_data('config_db_port', 5432)
    network.nodes['node_2'].put_data('service_timeout', 30)

    # 等待数据传播
    print("\n--- 等待数据传播 (10秒) ---")
    time.sleep(10)

    # 检查数据同步情况
    print("\n--- 数据同步检查 ---")
    status = network.get_network_status()
    for node_id, node_status in status.items():
        print(f"{node_id}: {node_status['data_count']} items, {node_status['peer_count']} peers")

    # 检查具体数据
    print("\n--- 数据内容检查 ---")
    test_key = 'config_db_host'
    for node_id, node in network.nodes.items():
        value = node.get_data(test_key)
        print(f"{node_id}.{test_key} = {value}")

    # 更新数据
    print("\n--- 更新数据 ---")
    network.nodes['node_3'].put_data('config_db_host', 'db2.example.com')

    # 等待更新传播
    time.sleep(5)

    # 再次检查
    print("\n--- 更新后检查 ---")
    for node_id, node in network.nodes.items():
        value = node.get_data('config_db_host')
        print(f"{node_id}.config_db_host = {value}")

    # 显示最终状态
    print("\n--- 最终网络状态 ---")
    final_status = network.get_network_status()
    for node_id, node_status in final_status.items():
        print(f"{node_id}:")
        print(f"  Peers: {node_status['peers']}")
        print(f"  Members: {node_status['members']}")
        print(f"  Data count: {node_status['data_count']}")

    # 清理
    network.stop_network()


if __name__ == "__main__":
    # 设置更详细的日志
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # 运行演示
    demo_gossip_network()